module TB_Y86(
////////////////////	Clock Input	 	////////////////////	 
CLOCK_27,						//	27 MHz
CLOCK_50,						//	50 MHz
EXT_CLOCK,						//	External Clock
////////////////////	Push Button		////////////////////
KEY,							//	Pushbutton[3:0]
////////////////////	DPDT Switch		////////////////////
SW,								//	Toggle Switch[17:0]
///////////////////// LEDS /////////////////////////////
LEDG,
LEDR,
//////////////////// HEX Display //////////////////////
HEX0,
HEX1,
HEX2,
HEX3,
HEX4,
HEX5,
HEX6,
HEX7,
////////////////////	SRAM Interface		////////////////
SRAM_DQ,						//	SRAM Data bus 16 Bits
SRAM_ADDR,						//	SRAM Address bus 18 Bits
SRAM_UB_N,						//	SRAM High-byte Data Mask 
SRAM_LB_N,						//	SRAM Low-byte Data Mask 
SRAM_WE_N,						//	SRAM Write Enable
SRAM_CE_N,						//	SRAM Chip Enable
SRAM_OE_N,						//	SRAM Output Enable
////////////////////	VGA		////////////////////////////
VGA_CLK,   						//	VGA Clock
VGA_HS,							//	VGA H_SYNC
VGA_VS,							//	VGA V_SYNC
VGA_BLANK,						//	VGA BLANK
VGA_SYNC,						//	VGA SYNC
VGA_R,   						//	VGA Red[9:0]
VGA_G,	 						//	VGA Green[9:0]
VGA_B,  							//	VGA Blue[9:0]
);


input CLOCK_50;
input CLOCK_27;
input EXT_CLOCK;

////////////////////////	SRAM Interface	////////////////////////
inout	[15:0]	SRAM_DQ;				//	SRAM Data bus 16 Bits
output [17:0]	SRAM_ADDR;				//	SRAM Address bus 18 Bits
output			SRAM_UB_N;				//	SRAM High-byte Data Mask
output			SRAM_LB_N;				//	SRAM Low-byte Data Mask 
output			SRAM_WE_N;				//	SRAM Write Enable
output			SRAM_CE_N;				//	SRAM Chip Enable
output			SRAM_OE_N;				//	SRAM Output Enable

////////////// Key Button ///////////////////
input [17:0] SW;
input [3:0] KEY;

//////////////// LEDs ///////////////////////
output [17:0] LEDR;
output [8:0] LEDG;

//////////////// HEX ////////////////////////
output [6:0] HEX0;
output [6:0] HEX1;
output [6:0] HEX2;
output [6:0] HEX3;
output [6:0] HEX4;
output [6:0] HEX5;
output [6:0] HEX6;
output [6:0] HEX7;
/////////////////////////////////////////////

////////////////////////	VGA			////////////////////////////
output			VGA_CLK;   				//	VGA Clock
output			VGA_HS;					//	VGA H_SYNC
output			VGA_VS;					//	VGA V_SYNC
output			VGA_BLANK;				//	VGA BLANK
output			VGA_SYNC;				//	VGA SYNC
output	[9:0]	VGA_R;   				//	VGA Red[9:0]
output	[9:0]	VGA_G;	 				//	VGA Green[9:0]
output	[9:0]	VGA_B;   				//	VGA Blue[9:0]


///////////////// MEM /////////////////////
wire [31:0] mem_addr_p1;
wire [15:0] mem_data_i_p1;
wire [15:0] mem_data_o_p1;
wire mem_enable_p1;
wire mem_ub_p1;
wire mem_lb_p1;
wire mem_write_p1;
////////////////////////////////////////////

///////////////// FETCH ////////////////////
wire [31:0] fetch_addr_p1;
wire [15:0] fetch_data_o_p1;
wire fetch_lb_p1;
wire fetch_ub_p1;
wire wait_p1;
wire hold_p1;
///////////////////////////////////////////

///////////////// MEM /////////////////////
wire [31:0] mem_addr_p2;
wire [15:0] mem_data_i_p2;
wire [15:0] mem_data_o_p2;
wire mem_enable_p2;
wire mem_ub_p2;
wire mem_lb_p2;
wire mem_write_p2;
////////////////////////////////////////////

///////////////// FETCH ////////////////////
wire [31:0] fetch_addr_p2;
wire [15:0] fetch_data_o_p2;
wire fetch_lb_p2;
wire fetch_ub_p2;
wire wait_p2;
wire hold_p2;
///////////////////////////////////////////

///////////////// VGA /////////////////////
wire [17:0] VGA_ADDR;
wire [7:0] VGA_DATA;
reg V_SYNC;
wire VGA_WHICH_BYTE;
///////////////////////////////////////////

///////////////// ETC /////////////////////
reg [31:0] CK;
wire RESET;
reg CLOCK;
wire [31:0] debug_p1;
wire [3:0] CC_debug_p1;
wire [31:0] debug_p2;
wire [3:0] CC_debug_p2;
wire priority;
///////////////////////////////////////////

/////////////// VGA Controller ///////////
/*
wire clk_vga;
reg [0:0] cnt = 0;

always @(posedge CLOCK_50) cnt = cnt + 1;
assign clk_vga = cnt[0];

VGA_Controller vga(
						.reset(RESET), 
						.clk(clk_vga), 
						.VGA_CLK(VGA_CLK), 
						.VGA_HS(VGA_HS), 
						.VGA_VS(VGA_VS), 
						.VGA_BLANK(VGA_BLANK), 
						.VGA_SYNC(VGA_SYNC), 
						.VGA_R(VGA_R),
						.VGA_B(VGA_B), 
						.VGA_G(VGA_G),
						.VGA_ADDR(VGA_ADDR),
						.VGA_DATA(VGA_DATA),
						.VGA_WHICH_BYTE(VGA_WHICH_BYTE));

*/
////////////// BUS//////////////

BUS bus(
		.CLOCK(CLOCK),
		.PRIORITY(priority),
		.SRAM_ADDR(SRAM_ADDR),
      .SRAM_DATA(SRAM_DQ),
      .WE_N(SRAM_WE_N),
      .OE_N(SRAM_OE_N),
      .UB_N(SRAM_UB_N),
      .LB_N(SRAM_LB_N),
      .CE_N(SRAM_CE_N),
		.VGA_ADDR(VGA_ADDR),
		.VGA_DATA(VGA_DATA),
		.V_SYNC(VGA_VS),
		.VGA_WHICH_BYTE(VGA_WHICH_BYTE),
		.FETCH_ADDR_P1(fetch_addr_p1),
		.FETCH_DATA_OUT_P1(fetch_data_o_p1),
		.FETCH_UB_P1(fetch_ub_p1),
		.FETCH_LB_P1(fetch_lb_p1),
		.WAIT_P1(wait_p1),
		.HOLD_P1(hold_p1),
      .MEM_ADDR_P1(mem_addr_p1[17:0]),
      .MEM_DATA_IN_P1(mem_data_i_p1),
      .MEM_DATA_OUT_P1(mem_data_o_p1),
      .MEM_WRITE_P1(mem_write_p1),
      .MEM_UB_P1(mem_ub_p1),
      .MEM_LB_P1(mem_lb_p1),
		.MEM_ENABLE_P1(mem_enable_p1),
		.FETCH_ADDR_P2(fetch_addr_p2),
		.FETCH_DATA_OUT_P2(fetch_data_o_p2),
		.FETCH_UB_P2(fetch_ub_p2),
		.FETCH_LB_P2(fetch_lb_p2),
		.WAIT_P2(wait_p2),
		.HOLD_P2(hold_p2),
      .MEM_ADDR_P2(mem_addr_p2[17:0]),
      .MEM_DATA_IN_P2(mem_data_i_p2),
      .MEM_DATA_OUT_P2(mem_data_o_p2),
      .MEM_WRITE_P2(mem_write_p2),
      .MEM_UB_P2(mem_ub_p2),
      .MEM_LB_P2(mem_lb_p2),
		.MEM_ENABLE_P2(mem_enable_p2)
		);
			 
Y86_Controller y86_p1(.CLOCK(CLOCK), 
						 .reset(RESET),
						 .id(0), 
						 .fetch_addr(fetch_addr_p1),
						 .fetch_data_i(fetch_data_o_p1),
						 .fetch_ub(fetch_ub_p1),
						 .fetch_lb(fetch_lb_p1),
						 .mem_addr(mem_addr_p1), 
						 .mem_data_i(mem_data_o_p1), 
						 .mem_data_o(mem_data_i_p1),
						 .mem_write(mem_write_p1),
						 .mem_ub(mem_ub_p1),
						 .mem_lb(mem_lb_p1),
						 .mem_enable(mem_enable_p1),
						 .debug(debug_p1),
						 .CC_debug(CC_debug_p1),
						 .lock(hold_p1),
						 .hold(wait_p1));
						 

Y86_Controller y86_p2(.CLOCK(CLOCK), 
						 .reset(RESET), 
						 .id(1),
						 .fetch_addr(fetch_addr_p2),
						 .fetch_data_i(fetch_data_o_p2),
						 .fetch_ub(fetch_ub_p2),
						 .fetch_lb(fetch_lb_p2),
						 .mem_addr(mem_addr_p2), 
						 .mem_data_i(mem_data_o_p2), 
						 .mem_data_o(mem_data_i_p2),
						 .mem_write(mem_write_p2),
						 .mem_ub(mem_ub_p2),
						 .mem_lb(mem_lb_p2),
						 .mem_enable(mem_enable_p2),
						 .debug(debug_p2),
						 .CC_debug(CC_debug_p2),
						 .lock(hold_p2),
						 .hold(wait_p2));
					 
		
assign HEX7 = put(debug_p1[31:28]);
assign HEX6 = put(debug_p1[27:24]);
assign HEX5 = put(debug_p1[23:20]);
assign HEX4 = put(debug_p1[19:16]);

assign HEX3 = put(debug_p1[15:12]);
assign HEX2 = put(debug_p1[11:8]);
assign HEX1 = put(debug_p1[7:4]);
assign HEX0 = put(debug_p1[3:0]);

assign LEDG[0] = CC_debug_p1[0];
assign LEDG[1] = CC_debug_p1[1];
assign LEDG[2] = CC_debug_p1[2];
assign LEDG[3] = CC_debug_p1[3];
assign LEDG[4] = CC_debug_p2[0];
assign LEDG[5] = CC_debug_p2[1];
assign LEDG[6] = CC_debug_p2[2];
assign LEDG[7] = CC_debug_p2[3];

assign LEDG[8] = CLOCK;

assign LEDR = SW;

assign RESET = KEY[3];

always @(posedge CLOCK_50) CK <= CK + 17'd1;

always @(SW[17:0]) begin

  casex (SW[17:0]) // synopsys parallel_case full_case
	  18'b00_0000_0000_0000_0000: CLOCK = CLOCK_50;
	  18'bxx_xxxx_xxxx_xxxx_xxx1: CLOCK = KEY[2];
	  18'bxx_xxxx_xxxx_xxxx_xx10: CLOCK = CK[0];
	  18'bxx_xxxx_xxxx_xxxx_x100: CLOCK = CK[1];
	  18'bxx_xxxx_xxxx_xxxx_1000: CLOCK = CK[2];
	  18'bxx_xxxx_xxxx_xxx1_0000: CLOCK = CK[3];
	  18'bxx_xxxx_xxxx_xx10_0000: CLOCK = CK[4];
	  18'bxx_xxxx_xxxx_x100_0000: CLOCK = CK[5];
	  18'bxx_xxxx_xxxx_1000_0000: CLOCK = CK[6];
	  18'bxx_xxxx_xxx1_0000_0000: CLOCK = CK[7];
	  18'bxx_xxxx_xx10_0000_0000: CLOCK = CK[8];
	  18'bxx_xxxx_x100_0000_0000: CLOCK = CK[9];
	  18'bxx_xxxx_1000_0000_0000: CLOCK = CK[10];
	  18'bxx_xxx1_0000_0000_0000: CLOCK = CK[11];
	  18'bxx_xx10_0000_0000_0000: CLOCK = CK[12];
	  18'bxx_x100_0000_0000_0000: CLOCK = CK[13];
	  18'bxx_1000_0000_0000_0000: CLOCK = CK[14];
	  18'bx1_0000_0000_0000_0000: CLOCK = CK[15];
	  18'b10_0000_0000_0000_0000: CLOCK = CK[23];
  endcase
end

function [6:0] put;
	input [3:0] a;
	begin 
		case (a)
			0: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b1;
			end
			1: begin 
				put[0] = 1'b1;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b1;
				put[4] = 1'b1;
				put[5] = 1'b1;
				put[6] = 1'b1;
			end
			2: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b1;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b1;
				put[6] = 1'b0;
			end
			3: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b1;
				put[5] = 1'b1;
				put[6] = 1'b0;
			end
			4: begin
				put[0] = 1'b1;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b1;
				put[4] = 1'b1;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			5: begin
				put[0] = 1'b0;
				put[1] = 1'b1;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b1;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			6: begin
				put[0] = 1'b0;
				put[1] = 1'b1;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			7: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b1;
				put[4] = 1'b1;
				put[5] = 1'b1;
				put[6] = 1'b1;
			end
			8: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			9: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b1;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			10: begin
				put[0] = 1'b0;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b1;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			11: begin
				put[0] = 1'b1;
				put[1] = 1'b1;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			12: begin
				put[0] = 1'b0;
				put[1] = 1'b1;
				put[2] = 1'b1;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b1;
			end
			13: begin
				put[0] = 1'b1;
				put[1] = 1'b0;
				put[2] = 1'b0;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b1;
				put[6] = 1'b0;
			end
			14: begin
				put[0] = 1'b0;
				put[1] = 1'b1;
				put[2] = 1'b1;
				put[3] = 1'b0;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			15: begin
				put[0] = 1'b0;
				put[1] = 1'b1;
				put[2] = 1'b1;
				put[3] = 1'b1;
				put[4] = 1'b0;
				put[5] = 1'b0;
				put[6] = 1'b0;
			end
			default: begin
				put[0] = 1'b1;
				put[1] = 1'b1;
				put[2] = 1'b1;
				put[3] = 1'b1;
				put[4] = 1'b1;
				put[5] = 1'b1;
				put[6] = 1'b1;
			end
		endcase
	end
endfunction


endmodule